package Negocio;

import ManejoExc.*;
import Ordenamiento.OrdenTipoInsumo;
import Ordenamiento.OrdenTipoRol;
import java.util.ArrayList;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import Persistencia.Persistencia;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.sql.Date;
import java.util.List;
import java.util.Map;

import Utils.*;
import java.sql.Time;
import java.util.Collections;
import java.util.LinkedList;

/**
 * @author Diego
 * @version 1.0
 * @created 28-sep-2013 21:38:58 p.m.
 *
 * Reveer Relaciones y todo lo demas
 */
public class Empresa {

    private Integer idEmpresa;
    private String cuit;
    private String direccion;
    private String localidad;
    private String razonSocial;
    private int nroLegajo;
    private Map<String, Proveedor> proveedores; //cuit
    private Map<String, Cliente> clientes;
    private Set<Deposito> depositos;
    private Set<Ingreso> ingresos;
    private Set<ZonaDeDescarga> zonasDeDescargas;
    private Map<String, Personal> empleados; //cuil
    private Set<Salida> salidas;
    private Set<Plantacion> plantaciones;

    private Map<String, Vehiculo> vehiculos;
    private Set<Mantenimiento> mantenimientos;
    private List<TipoRol> tipoDeRoles;
    //private Set<Rol> roles;

    private Set<Insumo> insumos;
    private List<TipoDeInsumo> tiposDeInsumos;

    private Set<TipoMadera> tiposmaderas;

    //private Crypt miClaseEncriptadora;
    public final static Crypt miClaseEncriptadora = new Crypt();
    public final static FechaUtil miUtilidadDeFechas = new FechaUtil();
    public final static Persistencia persistencia = new Persistencia();

    //Constructores
    public Empresa() {

    }

    //Set & Get
    public Set<Plantacion> getPlantaciones() {
        return plantaciones;
    }

    public Set<Plantacion> getPlantacionesActivas() {
        Set<Plantacion> lista = new HashSet();
        Plantacion pl;
        Iterator it = this.getPlantaciones().iterator();
        while (it.hasNext()) {
            pl = (Plantacion) it.next();
            if (pl.getActiva()) {
                lista.add(pl);
            }
        }
        return lista;
    }

    public void setPlantaciones(Set<Plantacion> plantaciones) {
        this.plantaciones = plantaciones;
    }

    public Set<Mantenimiento> getMantenimientos() {
        return mantenimientos;
    }

    public void setMantenimientos(Set<Mantenimiento> mantenimientos) {
        this.mantenimientos = mantenimientos;
    }

    public List<TipoDeInsumo> getTiposDeInsumos() {
        return tiposDeInsumos;
    }

    public List<TipoDeInsumo> getTiposDeInsumosActivos() {
        List<TipoDeInsumo> lista = new LinkedList();
        for (TipoDeInsumo tdi : this.getTiposDeInsumos()) {
            if (tdi.getActivo()) {
                lista.add(tdi);
            }
        }
        return lista;
    }

    public void setTiposDeInsumos(List<TipoDeInsumo> tiposDeInsumos) {
        this.tiposDeInsumos = tiposDeInsumos;
    }

    public Map<String, Cliente> getClientes() {
        return clientes;
    }

    public void setClientes(Map<String, Cliente> clientes) {
        this.clientes = clientes;
    }

    public Map<String, Vehiculo> getVehiculos() {
        return vehiculos;
    }

    public void setVehiculos(Map<String, Vehiculo> vehiculos) {
        this.vehiculos = vehiculos;
    }

    public Map<String, Agricola> getAgricolas() {
        //Map<String, Vehiculo> vehiculos = this.getVehiculos();

        Map<String, Agricola> agricolas = new HashMap();
        Vehiculo unVehiculo;
        for (Map.Entry vehiculo : this.getVehiculos().entrySet()) {
            unVehiculo = ((Vehiculo) vehiculo.getValue());
            if (unVehiculo.isAgricola()) {
                agricolas.put(unVehiculo.getMatricula(), (Agricola) unVehiculo);
            }
        }

        return agricolas;

    }

    public Set<ZonaDeDescarga> getZonasDeDescargas() {
        return zonasDeDescargas;
    }

    public void setZonasDeDescargas(Set<ZonaDeDescarga> zonasDeDescargas) {
        this.zonasDeDescargas = zonasDeDescargas;
    }

    public Integer getIdEmpresa() {
        return idEmpresa;
    }

    public void setIdEmpresa(Integer idEmpresa) {
        this.idEmpresa = idEmpresa;
    }

    public String getCuit() {
        return cuit;
    }

    public void setCuit(String cuit) {
        this.cuit = cuit;
    }

    public String getDireccion() {
        return direccion;
    }

    public void setDireccion(String direccion) {
        this.direccion = direccion;
    }

    public String getLocalidad() {
        return localidad;
    }

    public void setLocalidad(String localidad) {
        this.localidad = localidad;
    }

    public String getRazonSocial() {
        return razonSocial;
    }

    public void setRazonSocial(String razonSocial) {
        this.razonSocial = razonSocial;
    }

    public int getNroLegajo() {
        return nroLegajo;
    }

    public void setNroLegajo(int nroLegajo) {
        this.nroLegajo = nroLegajo;
    }

    public Map<String, Proveedor> getProveedores() {
        return proveedores;
    }

    public Map<String, Proveedor> getProveedoresActivos() {
        Map<String, Proveedor> salida = new HashMap();
        Proveedor unProveedor;
        for (Map.Entry proveedor : this.getProveedores().entrySet()) {
            unProveedor = ((Proveedor) proveedor.getValue());
            if (unProveedor.getActivo()) {
                salida.put(unProveedor.getCuit(), unProveedor);
            }
        }

        return salida;
    }

    public void setProveedores(Map<String, Proveedor> proveedores) {
        this.proveedores = proveedores;
    }

    public Set<Deposito> getDepositos() {
        return depositos;
    }

    public void setDepositos(Set<Deposito> depositos) {
        this.depositos = depositos;
    }

    public Set<Ingreso> getIngresos() {
        return ingresos;
    }

    public void setIngresos(Set<Ingreso> ingresos) {
        this.ingresos = ingresos;
    }

    public Set<ZonaDeDescarga> getZdls() {
        return this.zonasDeDescargas;
    }

    public void setZdls(Set<ZonaDeDescarga> zonasDeDescargas) {
        this.zonasDeDescargas = zonasDeDescargas;
    }

    public Map<String, Personal> getEmpleados() {
        return this.empleados;
    }

    public void setEmpleados(Map<String, Personal> empleados) {
        this.empleados = empleados;
    }

    public Set<Salida> getSalidas() {
        return salidas;
    }

    public void setSalidas(Set<Salida> salidas) {
        this.salidas = salidas;
    }

    public List<TipoRol> getTipoDeRoles() {
        return tipoDeRoles;
    }

    public List<TipoRol> getTipoDeRolesActivos() {
        List<TipoRol> lista = new LinkedList();
        TipoRol unTipo;
        Iterator it = this.getTipoDeRoles().iterator();
        while (it.hasNext()) {
            unTipo = (TipoRol) it.next();
            if (unTipo.getActivo()) {
                lista.add(unTipo);
            }
        }

        return lista;
    }

    public void setTipoDeRoles(List<TipoRol> tipoDeRoles) {
        this.tipoDeRoles = tipoDeRoles;
    }

    public Set<Insumo> getInsumos() {
        return insumos;
    }

    public void setInsumos(Set<Insumo> insumos) {
        this.insumos = insumos;
    }

    public Set<TipoMadera> getTiposmaderas() {
        return tiposmaderas;
    }

    public void setTiposmaderas(Set<TipoMadera> tiposmaderas) {
        this.tiposmaderas = tiposmaderas;
    }

    //Metodos
    public void agregarIngreso(Ingreso unIngreso) {
        this.ingresos.add(unIngreso);
        Empresa.persistencia.update(this);
    }

    public Set<Ingreso> obtenerIngresos() {
        return this.ingresos;
    }

    public void actualizarDeposito(Deposito unDeposito, String unNombre, int capacidad) throws EmpresaException {
        if (this.verificarNombreDeposito(unDeposito, unNombre)) {
            unDeposito.actualizar(unNombre, capacidad);
        }
    }

    public void agergarDeposito(Deposito unDeposito) {
        this.depositos.add(unDeposito);
        Empresa.persistencia.update(this);
    }

    public void nuevoDeposito(String unNombre, int capacidad) throws EmpresaException {
        if (this.verificarNombreDeposito(unNombre)) {
            this.agergarDeposito(new Deposito(unNombre, capacidad));
        }
    }

    public boolean verificarNombreDeposito(String unNombre) throws EmpresaException {
        boolean salida = true;
        Deposito unDeposito;
        if (unNombre.trim().equals("")) {
            salida = false;
            throw new EmpresaException("El nombre del deposito no puede estar vacio. Verifique");
        }

        Iterator it = this.getDepositos().iterator();
        while (it.hasNext() & salida) {
            unDeposito = (Deposito) it.next();
            if (unDeposito.getNombre().equals(unNombre.trim())) {
                salida = false;
                throw new EmpresaException("El nombre del deposito ya se ha ingresado. Verifique");
            }
        }
        return salida;
    }

    public boolean verificarNombreDeposito(Deposito miDeposito, String unNombre) throws EmpresaException {
        boolean salida = true;
        Deposito unDeposito;
        if (unNombre.trim().equals("")) {
            salida = false;
            throw new EmpresaException("El nombre del deposito no puede estar vacio. Verifique");
        }

        Iterator it = this.getDepositos().iterator();
        while (it.hasNext() & salida) {
            unDeposito = (Deposito) it.next();
            if (!unDeposito.equals(miDeposito) && unDeposito.getNombre().equals(unNombre.trim())) {
                salida = false;
                throw new EmpresaException("El nombre del deposito ya se ha ingresado. Verifique");
            }
        }
        return salida;
    }

    public void agregarZdl(ZonaDeDescarga unaZonaDeDescarga) {
        this.zonasDeDescargas.add(unaZonaDeDescarga);
    }

    public void agregarEmpleado(Personal unEmpleado) {
        this.empleados.put(unEmpleado.getClave(), unEmpleado);
    }

    public void agregarSalida(Salida unaSalida) {
        this.salidas.add(unaSalida);
    }

    public boolean existeMatricula(String unaMatricula) {
        return this.vehiculos.containsKey(unaMatricula);
    }

    public void agregarRodado(Rodado unVehiculo) throws VehiculoException, Exception {

        if (!this.existeMatricula(unVehiculo.getMatricula())) {
            this.vehiculos.put(unVehiculo.getMatricula(), unVehiculo);
        } else {
            throw new Exception("Matricula Existente Verifique");
        }
    }

    public void agregarAgricola(Agricola unVehiculo) throws VehiculoException, Exception {

        if (!this.existeMatricula(unVehiculo.getMatricula())) {
            this.vehiculos.put(unVehiculo.getMatricula(), unVehiculo);
        } else {
            throw new Exception("Matricula Existente Verifique");
        }
    }

    public void nuevoVehiculoRodado(String matricula, Integer modelo, Integer interno, Integer kilometraje, String estado) throws VehiculoException, Exception {
        Rodado unRodado = new Rodado(matricula, modelo, interno, kilometraje, estado);
        this.agregarRodado(unRodado);
        Empresa.persistencia.update(this);

    }

    public void nuevoVehiculoAgricola(String matricula, int modelo, int interno, int horas_uso, int tara, String estado) throws VehiculoException, Exception {
        Agricola unAgricola = new Agricola(horas_uso, tara, matricula, modelo, interno, estado);
        this.agregarAgricola(unAgricola);
        Empresa.persistencia.update(this);
    }

    public void modificarAgricola(Agricola unAgricola, String matricula, int modelo, int interno, int horas_uso, int tara, String estado) throws VehiculoException, Exception {
        //si la matricula no cambio actualizo

        if (!unAgricola.getMatricula().equals(matricula) && !this.existeMatricula(matricula)) { //Si la matricula cambio y no esta en el map actualizo
            this.vehiculos.remove(unAgricola.getMatricula());
        }
        unAgricola.modificar(matricula, modelo, interno, horas_uso, tara, estado);
        this.vehiculos.put(unAgricola.getMatricula(), unAgricola);
        Empresa.persistencia.update(this);
    }

    public void modificarRodado(Rodado unRodado, String matricula, Integer modelo, Integer interno, Integer kilometraje, String estado) throws VehiculoException, Exception {
        if (!unRodado.getMatricula().equals(matricula) && !this.existeMatricula(matricula)) { //Si la matricula cambio y no esta en el map actualizo
            this.vehiculos.remove(unRodado.getMatricula());
        }
        unRodado.modificar(matricula, modelo, interno, estado, kilometraje);
        this.vehiculos.put(unRodado.getMatricula(), unRodado);
        Empresa.persistencia.update(this);
    }

    public void quitarVehiculo(Vehiculo unVehiculo) {
        unVehiculo.deshabilitar();
        this.vehiculos.put(unVehiculo.getMatricula(), unVehiculo);
        Empresa.persistencia.update(this);

    }

    public Map<String, Vehiculo> getVehiculosActivos() {

        Vehiculo unVehiculo;
        Map<String, Vehiculo> lst = new HashMap();

        for (Map.Entry vehiculo : this.getVehiculos().entrySet()) {
            unVehiculo = ((Vehiculo) vehiculo.getValue());
            if (unVehiculo.getActivo()) {
                lst.put(unVehiculo.getMatricula(), unVehiculo);
            }
        }
        return lst;
    }

    public void agregarTipoRol(TipoRol unTipoRol) {
        this.tipoDeRoles.add(unTipoRol);
        Empresa.persistencia.update(this);
    }

    public boolean existeTipoRol(String unNombre) throws ExcepcionRol {
        boolean salida = true;
        TipoRol unTipo;
        if (!unNombre.trim().equals("")) {
            Iterator it = this.getTipoDeRoles().iterator();
            while (it.hasNext() & salida) {
                unTipo = (TipoRol) it.next();
                if (unTipo.getNombre().equals(unNombre) && unTipo.getActivo()) {
                    salida = false;
                }
            }
        } else {
            throw new ExcepcionRol("El nombre ingresado no puede ser vacio. Verifique");
        }

        return !salida;
    }

    public void nuevoTipoRol(String nombre) throws ExcepcionRol {
        if (!this.existeTipoRol(nombre)) {
            TipoRol unTipo = new TipoRol(nombre);
            this.agregarTipoRol(unTipo);
        } else {
            throw new ExcepcionRol("El nombre ingresado para el Tipo de Rol existe. Verifique");
        }

    }

    public TipoRol getTipoRol(String unNombreRol) throws ExcepcionRol {
        TipoRol tr;// = null;
        TipoRol rolReturn = null;
        Iterator it = this.tipoDeRoles.iterator();
        while (it.hasNext()) {
            tr = (TipoRol) it.next();
            if (tr.isTipoRol(unNombreRol)) { // si el parametro es como se llama el tipo de ron
                rolReturn = tr;
            }
        }
        if (rolReturn == null) {
            throw new ExcepcionRol("Tipo de Rol: " + unNombreRol + " no Encontrado");
        }
        return rolReturn;
    }

    //Incorporo insumos a la empresa
    public void agregarInsumo(Insumo unInsumo) {
        this.insumos.add(unInsumo);
        Empresa.persistencia.update(this);
    }

    public void nuevoInsumo(TipoDeInsumo tipoDeInsumo, Integer cantidad) {
        Insumo unInsumo = new Insumo(tipoDeInsumo, cantidad);
        this.agregarInsumo(unInsumo);
    }

    public void actualizarInsumo(Insumo unInsumo, int unaCantidad) {
        unInsumo.actualizarInsumo(unaCantidad);

    }

    public boolean existeCuitProveedor(String unaCuit) {
        return this.proveedores.containsKey(unaCuit);
    }

    public boolean validarDatosProveedor(String cuit, String direccion, String email, String razonsocial) throws ProveedorException {
        boolean salida = true;
        if (existeCuitProveedor(cuit)) {
            throw new ProveedorException("La CUIT ingresada ya existe. Verifique");
        }

        if (cuit.trim().equals("") || direccion.trim().equals("") || email.trim().equals("") || razonsocial.trim().equals("")) {
            throw new ProveedorException("La los campos no pueden estar vacios. Verifique");
        }

        return salida;
    }

    public boolean validarDatosProveedor(Proveedor unProveedor, String cuit, String direccion, String email, String razonsocial) throws ProveedorException {
        boolean salida = true;
        if (!this.proveedores.get(cuit).getCuit().equals(cuit)) {
            throw new ProveedorException("La CUIT ingresada ya existe. Verifique");
        }

        if (cuit.trim().equals("") || direccion.trim().equals("") || email.trim().equals("") || razonsocial.trim().equals("")) {
            throw new ProveedorException("La los campos no pueden estar vacios. Verifique");
        }

        return salida;
    }

    public void nuevoProveedor(String cuit, String direccion, String email, String razonsocial) throws ProveedorException {
        if (this.validarDatosProveedor(cuit, direccion, email, razonsocial)) {
            this.agregarProveedor(new Proveedor(cuit, direccion, email, razonsocial));
        }
    }

    public void agregarProveedor(Proveedor unProveedor) {

        this.proveedores.put(unProveedor.getCuit(), unProveedor);
        Empresa.persistencia.update(this);
    }

    public void actulizarProveedor(Proveedor unProveedor, String unaCuit, String unaDireccion, String unEmail, String unaRazonSocial) throws ProveedorException {
        if (this.validarDatosProveedor(unProveedor, unaCuit, unaDireccion, unEmail, unaRazonSocial)) {
            unProveedor.actualizar(unaCuit, unaDireccion, unEmail, unaRazonSocial);
            Empresa.persistencia.update(this);
        }

    }

    /*
     public void bajaPersonal(Personal unPersonal) {
     unPersonal.darDeBaja();
     }
     */
    public Set<Personal> personalActivo() {
        //retorno coleccion con personal activo
        Personal unPersonal;
        Set<Personal> personalesActivos = new HashSet();

        Iterator it = this.empleados.values().iterator();
        while (it.hasNext()) {
            unPersonal = (Personal) it.next();
            if (unPersonal.getActivo()) {
                personalesActivos.add(unPersonal);
            }
        }

        return personalesActivos;
    }

    //Alta personal
    //Si solo fue dado de baja
    //public void altaPersonal(String unaCuil, TipoRol unTipoRol) {
    //    this.empleados.get(unaCuil).darAlta(unTipoRol);
    //}
    //Creo el Empleado desde 0
    //String apellido, String cuil, Date fechaNacimiento, String nombre, int legajo, boolean activo, ArrayList<Equipamiento> equipamientos, ArrayList<RegistroHorario> registroHorarios, ArrayList<Rol> roles
    public void nuevoPersonal(String apellido, String cuil, String dni, Date fechaNacimiento, String nombre) throws PersonalException {
        //Creo la instancia de personal        
        if (!this.existeCuil(cuil)) { //Si no existe                
            if (this.validarDatosPersonal(apellido, cuil, dni, fechaNacimiento, nombre)) {
                Personal unPersonal = new Personal(apellido, cuil, dni, fechaNacimiento, nombre, this.siguienteLegajo());
                this.agregarEmpleado(unPersonal);
                Empresa.persistencia.update(this);
            } else {
                throw new PersonalException("Verifique que los datos ingresados.");
            }

        } else {
            throw new PersonalException("La Cuil ingresada ya existe, verifique");
        }    //

    }

    public boolean validarDatosPersonal(String apellido, String cuil, String dni, Date fechaNacimiento, String nombre) {
        boolean salida = true;
        if (apellido.trim().equals("") || cuil.trim().equals("") || dni.trim().equals("") || nombre.trim().equals("")) {
            salida = false;
        }
        return salida;
    }

    public void modificarPersonal(Personal unPersonal, String apellido, String cuil, String dni, Date fechaNacimiento, String nombre) throws PersonalException {

        //si no camio la cuil
        if (unPersonal.getCuil().equals(cuil)) {
            unPersonal.modificarDatos(apellido, cuil, dni, fechaNacimiento, nombre);

        } else {
            //si cambio la cuil
            //busco que no existe
            if (!this.existeCuil(cuil)) {
                unPersonal.modificarDatos(apellido, cuil, dni, fechaNacimiento, nombre);
                this.empleados.remove(unPersonal.getCuil());
            } else {
                throw new PersonalException("Cuil inexistente verifique");
            }
        }
        this.empleados.put(unPersonal.getCuil(), unPersonal);
        Empresa.persistencia.update(this);

    }

    public void bajaEmpleado(Personal unPersonal) {
        unPersonal.darDeBaja();
    }

    public boolean existeCuil(String unaCuil) {
        return this.empleados.containsKey(unaCuil);
    }

    public int siguienteLegajo() {
        int nrLegajo = this.nroLegajo;
        this.nroLegajo = this.nroLegajo + 1;
        return nrLegajo;
    }

    public void actualizarTipoRol(TipoRol unTipo, String unaDescripcion) {
        this.tipoDeRoles.remove(unTipo);
        unTipo.actualizar(unaDescripcion);
        this.agregarTipoRol(unTipo);
        Empresa.persistencia.update(this);
    }

    public boolean validarDatosCliente(String razonSocial, String unaCuit, String direccion, String password) throws ClienteException {
        boolean salida = true;
        if (razonSocial.trim().equals("") || unaCuit.trim().equals("") || direccion.trim().equals("") || password.trim().equals("")) {
            salida = false;
            throw new ClienteException("No pueden quedar campos obligatorios vacios. Verifique", 2);
        }
        return salida;
    }

    public void nuevoCliente(String razonSocial, String unaCuit, String direccion, String telefono, String password, String email) throws  ClienteException {

        if (this.validarDatosCliente(razonSocial, unaCuit, direccion, password) && this.existeClietne(unaCuit)) {            
            Cliente unCliente = new Cliente(razonSocial, unaCuit, direccion, telefono, password, email);
            this.agregarCliente(unCliente);
        }
    }

    public void agregarCliente(Cliente unCliente) {
        this.clientes.put(unCliente.getCuit(), unCliente);
        Empresa.persistencia.update(this);
    }

    public boolean existeClietne(String unaCuit) throws ClienteException {
        boolean salida = false;
        if (this.buscarCuitCliente(unaCuit)) {
            salida = true;
        }

        return salida;
    }

    public boolean buscarCuitCliente(String unaCuit) throws ClienteException {
        boolean salida = true;

        if (this.clientes.containsKey(unaCuit)) {
            throw new ClienteException("Cuit Repetida. Verifique", 3);
        }
        return salida;
    }

    public boolean buscarUserNameCliente(String userName) throws ClienteException {
        boolean salida = this.clientes.containsKey(userName);
        if (salida) {
            throw new ClienteException("UserName Repetido. Verifique", 3);
        }
        return salida;
    }

    public Cliente validarCliente(String userName, String pass) throws ClienteException {
        Cliente unCliente = this.clientes.get(userName);
        if (unCliente == null) {
            throw new ClienteException("Usuario invalido.", 1);
        }
        if(!unCliente.getPassword().equals(pass)){
            throw new ClienteException("Contraseña invalida.", 1);
        }
        return unCliente;
    }

    public boolean validarDatosTipoDeInsumo(String unNombre, String unaUnidad) throws InsumoException {
        boolean salida = true;
        if (unNombre.trim().equals("") || unaUnidad.trim().equals("")) {
            throw new InsumoException("Los campos no pueden estar vacios. Verifique");
        }
        return salida;
    }

    public void nuevoTipoDeInsumo(String unNombre, String unaDescripcion, String unaUnidad) throws InsumoException {
        if (this.validarDatosTipoDeInsumo(unNombre, unaUnidad)) {
            TipoDeInsumo unTipo = new TipoDeInsumo(unNombre, unaDescripcion, unaUnidad);
            this.agregarTipoDeInsumo(unTipo);
        }
    }

    public boolean ExisteTipoDeInsumo(TipoDeInsumo unTipo, String unNombre) throws InsumoException {
        boolean salida = true;
        Iterator it = this.getTiposDeInsumos().iterator();
        while (it.hasNext() && salida) {
            TipoDeInsumo unTipoInsumo = (TipoDeInsumo) it.next();
            if (unTipoInsumo.equals(unTipo) && unTipoInsumo.getActivo() && !unTipoInsumo.equals(unTipo)) {
                salida = false;
                throw new InsumoException("El Nombre ya ha sido ingresado. Verifique");
            }

        }

        return !salida;
    }

    public void agregarTipoDeInsumo(TipoDeInsumo unTipo) {
        this.tiposDeInsumos.add(unTipo);
        Empresa.persistencia.update(this);
    }

    public Set<Cliente> getClientesActivos() {
        /*        Cliente unCliente;
         Set<Cliente> result = new HashSet();
         Iterator it = this.clientes.entrySet().iterator();
         while (it.hasNext()) {
         unCliente = (Cliente) it.next();
         if (unCliente.isActivo()) {
         result.add(unCliente);
         }
         }
        
         */
        Cliente unCliente;
        Set<Cliente> result = new HashSet();
        for (Map.Entry cliente : this.getClientes().entrySet()) {
            Cliente elCliente = ((Cliente) cliente.getValue());
            /*if (elCliente.getActivo()) {
             result.add(elCliente);
             }*/
            result.add(elCliente);
        }
        return result;
    }

    public void actualizarLogin(Cliente unCliente, String unPass) throws ClienteException {
        //busco si el userName se puede usar        
        unCliente.actualizarPass(unPass);

    }

    public void actualizarDatosCliente(Cliente unCliente, String unaRazonSocial, String unaCuit, String unaDireccion, String untTelefono, String pass, String unEmail) throws ClienteException {
        this.actualizarDatosCliente(unCliente, unaRazonSocial, unaCuit, unaDireccion, untTelefono, unEmail);
        this.actualizarLogin(unCliente, pass);
        Empresa.persistencia.update(this);

    }

    public void actualizarDatosCliente(Cliente unCliente, String unaRazonSocial, String unaCuit, String unaDireccion, String untTelefono, String unEmail) throws ClienteException {

        if (this.validarDatosCliente(razonSocial, unaCuit, direccion, unEmail)) {
            if (unCliente.getCuit().equals(unaCuit)) {
                //solo actualizo             
                unCliente.actualizarDatos(unaRazonSocial, unaCuit, unaDireccion, untTelefono, unEmail);

            } else if (!unCliente.getCuit().equals(unaCuit) && !this.existeCuitCliente(unaCuit)) { // cambio la cuit pero no existe             
                //actualizo y cambio la clave
                this.clientes.remove(unCliente.getCuit());
                unCliente.actualizarDatos(unaRazonSocial, unaCuit, unaDireccion, untTelefono, unEmail);
            } else {
                //si la cuit cambio pero ya existe no se puede actualizar
                throw new ClienteException("Verifique la CUIT", 3);
            }
            this.agregarCliente(unCliente);
        }
    }

    public boolean existeCuitCliente(String unaCuit) {
        return this.clientes.containsKey(unaCuit);
    }

    public void agregarMantenimiento(Mantenimiento unMantenimiento) {
        this.mantenimientos.add(unMantenimiento);
        Empresa.persistencia.update(this);
    }

    //                             
    public void nuevoMantenimiento(Vehiculo unVehiculo, Personal unPersonal, Date fecha, String unasNotas) {
        Mantenimiento unMantenimiento = new Mantenimiento(fecha, unasNotas, unVehiculo, unPersonal);
        unVehiculo.agregarMantenimiento(unMantenimiento);
        this.agregarMantenimiento(unMantenimiento);

    }

    public void actualizarMantenimiento(Mantenimiento unMantenimiento, Date fecha, Personal unPersonal, Vehiculo unVehiculo, String unasNotas) {
        //this.unMantenimiento,unaFecha,this.unPersonal,this.unVehiculo,this.TxtNotas.getText()
        unMantenimiento.actualizar(fecha, unPersonal, unVehiculo, unasNotas);
        Empresa.persistencia.update(this);

    }

    public void quitarMantenimiento(Mantenimiento unMantenimiento) {
        this.mantenimientos.remove(unMantenimiento);
        unMantenimiento.getVehiculo().quitarMantenimiento(unMantenimiento);
        Empresa.persistencia.delete(unMantenimiento);
        Empresa.persistencia.update(this);

    }

    public void otorgarEquipamiento(Personal unPersonal, Insumo unInsumo, Date fecha, boolean obligatorio) throws PersonalException {

        unPersonal.agregarEquipamiento(new Equipamiento(fecha, unInsumo, obligatorio));
        this.reducirInventario(unInsumo);
    }

    public void reducirInventario(Insumo unInsumo) {
        unInsumo.setCantidad(unInsumo.getCantidad() - 1);
        Empresa.persistencia.update(unInsumo);
        Empresa.persistencia.update(this);
    }

    public boolean validarDatosPlantacion(String unNombre, String propietario) throws EmpresaException {
        boolean salida = true;
        if (unNombre.trim().equals("") || propietario.trim().equals("")) {
            throw new EmpresaException("Los campos no pueden estar vacios");
        }
        return salida;
    }

    public void nuevaPlantacion(String unNombre, String propietario, String ubicacion) throws EmpresaException {
        if (this.validarDatosPlantacion(unNombre, propietario)) {
            Plantacion unaPlantacion = new Plantacion(unNombre, propietario, ubicacion);
            this.agregarPlantacion(unaPlantacion);
        }
    }

    public void agregarPlantacion(Plantacion unaPlantacion) {
        this.plantaciones.add(unaPlantacion);
        Empresa.persistencia.update(this);
    }

    public void nuevaAplicacion(Date unaFecha, Parcela unaParcela, Personal unPersonal, Insumo unInsumo, Float unaCantidad) {

        //Creo la aplicacion
        //ate unaFecha,Parcela unaParcela,Personal unPersonal,Utilizacion unaUtilizacion
        Aplicacion aplic = new Aplicacion(unaFecha, unPersonal, unInsumo, unaCantidad);

        //
        unaParcela.agregarAplicacion(aplic);

    }

    public Map<String, Personal> getEmpleadosActivos() {
        Map<String, Personal> list = new HashMap();
        for (Map.Entry personal : this.getEmpleados().entrySet()) {
            Personal unEmp = ((Personal) personal.getValue());
            if (unEmp.getActivo()) {
                list.put(unEmp.getCuil(), unEmp);
            }

        }
        return list;
    }

    public List<TipoDeInsumo> ordenarTipoDeInsumo(List<TipoDeInsumo> lista, int criterio) {
        List<TipoDeInsumo> aux = new LinkedList();
        switch (criterio) {
            case 1:
                Collections.sort(lista, new OrdenTipoInsumo());
                break;
        }
        return aux;

    }

    public List<TipoRol> ordenarTipoRol(List<TipoRol> lista, int criterio) {
        List<TipoRol> aux = new LinkedList();
        switch (criterio) {
            case 1:
                Collections.sort(lista, new OrdenTipoRol());
                break;
        }
        return aux;

    }

    //public List  
    public void altaIngresoYerbaMateVerde(Date fecha, Time hora, Personal chofer, Agricola vehiculo,
            int pesoBruto, int pesoTara, int humedad, int palo, Parcela parcela, String origen,
            int kilaje, Seccion unaSeccion) throws MateriaPrimaException {
        //crear materia prima
        YerbaMateVerde materiaprima = new YerbaMateVerde(humedad, palo, false, parcela, origen, kilaje, fecha, hora);
        unaSeccion.agregarYerba(materiaprima);
        //crear ingreso
        Ingreso ingreso = new Ingreso(fecha, hora, materiaprima, chofer, vehiculo, pesoBruto, pesoTara);
        this.agregarIngreso(ingreso);
    }

    public void altaIngresoYerbaMateVerde(Date fecha, Time hora, Personal chofer, Agricola vehiculo,
            int pesoBruto, int pesoTara, int humedad, int palo, Parcela parcela, String origen,
            int kilaje, Seccion unaSeccion, Cliente unCliente) throws MateriaPrimaException {
        //crear materia prima
        YerbaMateVerde materiaprima = new YerbaMateVerde(humedad, palo, false, parcela, origen, kilaje, fecha, hora);
        unaSeccion.agregarYerba(materiaprima);
        materiaprima.setElCliente(unCliente);
        unCliente.agregarYerba(materiaprima);
        //crear ingreso
        Ingreso ingreso = new Ingreso(fecha, hora, materiaprima, chofer, vehiculo, pesoBruto, pesoTara);
        unCliente.agregarIngreso(ingreso);
        this.agregarIngreso(ingreso);
    }

    public void altaIngresoYerbaCanchada(Date fecha, Time hora, Personal chofer, Agricola vehiculo,
            int pesoBruto, int pesoTara, int polvo, int palo, Parcela parcela, String origen,
            int kilaje, Deposito unDeposito) throws MateriaPrimaException {
        //crear materia prima
        YerbaMateCanchada materiaprima = new YerbaMateCanchada(polvo, palo, parcela, origen, kilaje);
        //crear ingreso
        Ingreso ingreso = new Ingreso(fecha, hora, materiaprima, chofer, vehiculo, pesoBruto, pesoTara);
        this.agregarIngreso(ingreso);
        if (origen.equals("propio")) {
            LotePropio unLote = new LotePropio(materiaprima, unDeposito);
            unDeposito.agregarLote(unLote);
        } else {
            LoteTercero unLote = new LoteTercero(materiaprima, unDeposito);
            unDeposito.agregarLote(unLote);
        }
    }

    public void altaIngresoLeniaVerde(Date fecha, Time hora, Personal chofer, Agricola vehiculo,
            int pesoBruto, int pesoTara, int humedad, Parcela parcela, String origen,
            int kilaje) throws MateriaPrimaException {
        //crear materia prima
        LeniaVerde materiaprima = new LeniaVerde(humedad, false, kilaje, parcela, origen, kilaje);
        //crear ingreso
        Ingreso ingreso = new Ingreso(fecha, hora, materiaprima, chofer, vehiculo, pesoBruto, pesoTara);
        this.agregarIngreso(ingreso);
    }

    public void altaIngresoLeniaSeca(Date fecha, Time hora, Personal chofer, Agricola vehiculo,
            int pesoBruto, int pesoTara, TipoMadera tipoMadera, Parcela parcela, String origen,
            int kilaje) throws MateriaPrimaException {
        //crear materia prima
        LeniaSeca materiaprima = new LeniaSeca(tipoMadera, false, kilaje, parcela, origen, kilaje);
        //crear ingreso
        Ingreso ingreso = new Ingreso(fecha, hora, materiaprima, chofer, vehiculo, pesoBruto, pesoTara);
        this.agregarIngreso(ingreso);
    }

    public Seccion buscarSeccionDisponible(int kilos) {
        Seccion unaSeccion = null;
        boolean encontrado = false;
        Iterator it = this.zonasDeDescargas.iterator();
        while (it.hasNext() && !encontrado) {
            ZonaDeDescarga unaZonaDescarga = (ZonaDeDescarga) it.next();
            Set<Seccion> secciones = unaZonaDescarga.getSecciones();
            Iterator its = secciones.iterator();
            while (its.hasNext() && !encontrado) {
                Seccion laSeccion = (Seccion) its.next();
                if (laSeccion.estaLibre(kilos)) {
                    unaSeccion = laSeccion;
                    encontrado = true;
                }
            }
        }
        return unaSeccion;
    }

    public Deposito buscarDepositoDisponible(int kilos) {
        Deposito unDeposito = null;
        boolean encontrado = false;
        Iterator it = this.depositos.iterator();
        while (it.hasNext() && !encontrado) {
            Deposito elDeposito = (Deposito) it.next();
            if (elDeposito.estaLibre(kilos)) {
                unDeposito = elDeposito;
                encontrado = true;
            }
        }
        return unDeposito;
    }

    public Set<YerbaMateCanchada> getYerbaCanchada() {
        Set<YerbaMateCanchada> yerbaCanchada = new HashSet<>();
        for (Deposito elDeposito : this.depositos) {
            Set<Lote> losLotes = elDeposito.getLotes();
            for (Lote unLote : losLotes) {
                yerbaCanchada.add(unLote.getYerbaMateCanchada());
            }
        }
        return yerbaCanchada;
    }

    public int getCantidadYerbaCanchadaPropia() {
        int cant = 0;
        for (Deposito elDeposito : this.depositos) {
            Set<Lote> losLotes = elDeposito.getLotes();
            for (Lote unLote : losLotes) {
                if (unLote.getYerbaMateCanchada() != null) {
                    if (unLote.getYerbaMateCanchada().getOrigen().equals("propio")) {
                        cant += unLote.getYerbaMateCanchada().getKilaje();
                    }
                }
            }
        }
        return cant;
    }

    public int getCantidadYerbaVerdeComprada() {
        int cant = 0;
        for (ZonaDeDescarga unaZonaDescarga : this.zonasDeDescargas) {
            Set<Seccion> secciones = unaZonaDescarga.getSecciones();
            for (Seccion laSeccion : secciones) {
                Set<YerbaMateVerde> yerbaProcesar = laSeccion.getYerbaTerceros();
                for (YerbaMateVerde yerba : yerbaProcesar) {
                    cant += yerba.getKilaje();
                }
            }
        }
        return cant;
    }

    public Set<YerbaMateCanchada> getYerbaCanchadaPorDeposito(Deposito unDeposito, Cliente unCliente) {
        Set<YerbaMateCanchada> yerbaCanchada = new HashSet<>();
        for (Deposito elDeposito : this.depositos) {
            if (unDeposito.equals(elDeposito)) {
                Set<Lote> losLotes = elDeposito.getLotes();
                for (Lote unLote : losLotes) {
                    if (unLote instanceof LoteTercero) {
                        LoteTercero unLoteTercero = (LoteTercero) unLote;
                        if (unLoteTercero.getUnCliente().equals(unCliente)) {
                            yerbaCanchada.add(unLote.getYerbaMateCanchada());
                        }
                    } else {
                        yerbaCanchada.add(unLote.getYerbaMateCanchada());
                    }

                }
            }
        }
        return yerbaCanchada;
    }

    public Set<YerbaMateVerde> getYerbaVerdeParaProcesar() {
        Set<YerbaMateVerde> yerbaVerde = new HashSet<>();
        for (ZonaDeDescarga unaZonaDescarga : this.zonasDeDescargas) {
            Set<Seccion> secciones = unaZonaDescarga.getSecciones();
            for (Seccion laSeccion : secciones) {
                Set<YerbaMateVerde> yerbaProcesar = laSeccion.getYerbaParaProcesar();
                for (YerbaMateVerde yerba : yerbaProcesar) {
                    yerbaVerde.add(yerba);
                }
            }
        }
        return yerbaVerde;
    }

    public String procesarYerba(YerbaMateVerde yerbaVerde) {
        String resultado = "";
        int kilos = yerbaVerde.getKilaje();
        Deposito unDeposito = this.buscarDepositoDisponible(kilos);
        if (unDeposito != null) {
            if ("propio".equals(yerbaVerde.getOrigen())) {
                YerbaMateCanchada canchada = new YerbaMateCanchada(0, 0, yerbaVerde.getParcela(), "propio", kilos);
                LotePropio lotePropio = new LotePropio(canchada, unDeposito);
                unDeposito.agregarLote(lotePropio);
                yerbaVerde.setProcesado(true);
            } else {
                YerbaMateCanchada canchada = new YerbaMateCanchada(0, 0, yerbaVerde.getParcela(), "tercero", kilos);
                LoteTercero loteTercero = new LoteTercero(canchada, unDeposito);
                unDeposito.agregarLote(loteTercero);
                yerbaVerde.setProcesado(true);
                yerbaVerde.getElCliente().agregarLote(loteTercero);
                loteTercero.setUnCliente(yerbaVerde.getElCliente());
            }
        } else {
            resultado = "No hay depósito con capacidad disponible";
        }
        return resultado;
    }

    public void altaSalida(Personal unPersonal, Vehiculo unVehiculo, Date unaFecha, int kilaje, Lote unLote, Cliente unCliente) {
        Salida unaSalida = new Salida(unPersonal, unVehiculo, unaFecha, kilaje, unLote);
        unCliente.agregarSalida(unaSalida);
        this.salidas.add(unaSalida);
        Empresa.persistencia.update(this);
    }

    public Empresa(String unaCuit, String unaDireccion, String unaLocalidad, String unaRazonSocial) {
        this.cuit = unaCuit;
        this.direccion = unaDireccion;
        this.localidad = unaLocalidad;
        this.razonSocial = unaRazonSocial;
        this.nroLegajo = 1;

        //coleciones
        this.proveedores = new HashMap();//<String, Proveedor>();
        this.clientes = new HashMap();
        this.depositos = new HashSet();
        this.zonasDeDescargas = new HashSet();
        this.empleados = new HashMap();//<String, Personal>();
        this.salidas = new HashSet();
        this.mantenimientos = new HashSet();
        this.vehiculos = new HashMap();

        this.tipoDeRoles = new ArrayList();
        //this.roles = new HashSet();
        this.ingresos = new HashSet();
        this.insumos = new HashSet();
        this.plantaciones = new HashSet();

        this.tiposDeInsumos = new ArrayList();
        this.tiposmaderas = new HashSet();

        //Persisto la instancia creada
        Empresa.persistencia.insert(this);
    }

    /*
     public Set<Rol> getRoles() {
     return roles;
     }

     public void setRoles(Set<Rol> roles) {
     this.roles = roles;
     }
     */
    /*
     public void agregarRol(Rol unRol) {
     this.roles.add(unRol);
     }
     */

    /*
     public float horasTrabajadasPorRol(String unNombreRol, Date desde, Date hasta) throws ExcepcionRol {
     float hstrabajadas = this.getTipoRol(unNombreRol).horasTrabajadas(desde, hasta);
     return hstrabajadas;
     }
     */
    public TipoRol RolEmpleado(Personal unPersonal) {
        TipoRol unTipo = null, salida = null;

        boolean flag = true;
        Iterator it = this.getTipoDeRoles().iterator();
        while (it.hasNext() & flag) {
            unTipo = (TipoRol) it.next();
            if (unTipo.existeEmpleado(unPersonal)) {
                flag = false;
            }
        }
        if (!flag) {
            salida = unTipo;
        }
        return salida;
    }

    public Personal obtenerEmpleado(String unaCuil) throws PersonalException {
        Personal unPersonal = null;
        if (this.empleados.containsKey(unaCuil)) {
            unPersonal = this.empleados.get(unaCuil);
        } else {
            throw new PersonalException("Cuil invalida.Verifique");
        }
        return unPersonal;
    }

}
